/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.javlov.example.chain;

import net.javlov.Action;
import net.javlov.Agent;
import net.javlov.Environment;
import net.javlov.State;

import java.io.Serializable;
import java.util.*;

public class Chain implements Environment, Serializable {

	transient Node currentNode;
	transient List<Node> nodes;

	public Chain(int numNodes) {
		nodes = new ArrayList<Node>(numNodes);
		Node p = new Node(0, false);
		nodes.add(p);
		p.setPrevious(p);
		Node n;
		for ( int i = 1; i < numNodes-1; i++ ) {
			n = new Node(i, false);
			nodes.add(n);
			p.setNext(n);
			n.setPrevious(p);
			p = n;			
		}
		n = new Node(numNodes-1, true);
		p.setNext(n);
		n.setPrevious(p);
		n.setNext(n);
	}
	
	@Override
	public double executeAction(Action act, Agent a) {
		act.execute(a);
		return -1;
	}

	@Override
	public State getObservation(Agent a) {
		return currentNode;
	}

	@Override
	public int getObservationDim() {
		return 1;
	}

	@Override
	public void init() {
		reset();
	}

	@Override
	public void reset() {
		currentNode = nodes.get( (int)(Math.random()*nodes.size()) );
	}
	
	public Node currentNode() {
		return currentNode;
	}
	
	class Node extends State<Integer> {
		Node previous, next;

		public Node(int id, boolean terminal) {
			super(id, terminal);
		}
		
		public Node(Node prev, Node next, int id, boolean terminal) {
			this(id, terminal);
			previous = prev; this.next = next; 
		}
		
		void setPrevious(Node p) {
			previous = p;
		}
		
		void setNext(Node n) {
			next = n;
		}
		Node prev() {
			return previous;
		}
		Node next() {
			return next;
		}
	}

}
